//
//  NoticeBus.swift
//  Hanfu
//
//  Created by ZhouJiatao on 2018.02.27.
//  Copyright © 2018 EightEyes. All rights reserved.
//

import Foundation

/// 定义了许多,用于发送/接收指定的通知(注意,并没有使用NotificationCenter)
public class NoticeBus {
    struct StandardKeys {
        static let sender = "StandardKeysSender"
    }
    
    public typealias NoticeName = String
    
    public static let shared = NoticeBus()
    
    public enum Priority : Int {
        case hight = 0
        case normal
        case low
    }
    
    public struct Notice: Equatable {
        
        var targetAddress: UInt
        var name: NoticeName // 通知名
        var handler: (([AnyHashable:Any])->Void)
        
        public static func == (lhs: NoticeBus.Notice, rhs: NoticeBus.Notice) -> Bool {
            return (lhs.targetAddress == rhs.targetAddress && lhs.name == rhs.name)
        }
        
    }
    
    /// 按优先级共分为3个数组, 第0个索引的优先级最高,以此类推.
    private var noticeLayers = [[Notice](), [Notice](),[Notice]()]
    
    // 发送匿名通知
    //sender: 消息发送源; userInfo: 附带的信息.
    public func post(noticeName: NoticeName, sender: AnyObject = NoticeBus.shared, userInfo: [AnyHashable : Any] = [AnyHashable : Any]()) {
        print("NoticeBus: post '\(noticeName)' from '\(sender)' with info' \(userInfo) '" )
        for layer in noticeLayers {
            for notice in layer {
                if notice.name == noticeName {
                    var info = userInfo
                    info[StandardKeys.sender] = sender
                    DispatchQueue.main.async {
                        notice.handler(info)
                    }
                }
            }
        }
    }
    
    // 监听匿名通知
    public func on(_ target: AnyObject ,noticeName: NoticeName, priority: Priority = .normal, handler: @escaping (([AnyHashable:Any])->Void) ) {
        
        let id = UInt(bitPattern: ObjectIdentifier(target))
        
        let notice =  Notice(targetAddress: id, name: noticeName, handler: handler)
        
        if isExisted(notice) {
            return
        }
        
        noticeLayers[ priority.rawValue ].append(notice)
    }
    
    private func isExisted(_ notice: Notice) -> Bool{
        for priorityArr in noticeLayers {
            if priorityArr.contains(notice) {
                return true
            }
        }
        
        return false
    }
    
}
